import { AnimatePresence, motion } from "motion/react";
import React from "react";
import { uniqueID } from "~/utils";

interface NotificationProps {
  id?: string;
  msg: string;
  duration?: number;
  type?: "info" | "success" | "warning" | "error";
}

/**
 * Example
 * const { notifications, addNotification } = useNotification();
 * useEffect(() => {
     if (actionData?.message) {
       addNotification({ type: actionData?.code === 0 ? "success" : "error", msg: actionData.message });
     }
     if (actionData?.code === 0) {
       closeUserDialog();
     }
   }, [actionData, addNotification]);
 * In react component add this: <Notification notifications={notifications} />
 * @returns Notification component
 */

const useNotification = () => {
  const [notifications, setNotifications] = React.useState<NotificationProps[]>([]);
  const timerIds = React.useRef<{ [key: string]: NodeJS.Timeout }>({});

  const addNotification = React.useCallback((message: Omit<NotificationProps, 'id'>) => {
    const newMessage: NotificationProps = {
      id: uniqueID(),
      msg: message.msg,
      duration: message.duration ?? 3000,
      type: message.type ?? "info",
    };

    setNotifications(prevMessages => [...prevMessages, newMessage]);

    const timerId = setTimeout(() => {
      setNotifications(prevMessages => prevMessages.filter(msg => msg.id !== newMessage.id));
      delete timerIds.current[newMessage.id ?? ""];
    }, newMessage.duration);

    timerIds.current[newMessage.id ?? ""] = timerId;
  }, []);

  const removeNotification = React.useCallback((id: string) => {
    setNotifications(prevMessages => prevMessages.filter(msg => msg.id !== id));
    clearTimeout(timerIds.current[id]);
    delete timerIds.current[id];
  }, []);

  return { notifications, addNotification, removeNotification };
};
export default useNotification;

export const Notification: React.FC<{ notifications: NotificationProps[] }> = ({ notifications }) => {
  const alertType = {
    info: "alert alert-info",
    success: "alert alert-success",
    warning: "alert alert-warning",
    error: "alert alert-error",
  };

  return (
    <div className="toast toast-top toast-center">
      <AnimatePresence>
        {
          notifications.map(notification => (
            // The role of 'layout' keyword here is prevent the remaining elements shifting up without an animate when a preceding element is removed
            <motion.div key={notification.id} layout className={alertType[notification.type || "info"]} exit={{ opacity: 0 }}>
              <span>{notification.msg}</span>
            </motion.div>
          ))
        }
      </AnimatePresence>
    </div>
  )
};